import Axios, {
  AxiosInstance,
  AxiosRequestConfig,
  CustomParamsSerializer
} from "axios";
import {
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig
} from "./types.d";
import { stringify } from "qs";
import NProgress from "../progress";
import { getToken, formatToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
import { ElMessage, ElMessageBox } from "element-plus";
import mockList from "../../../mock/mock";

import { whReqBaseUrl as VITE_REQUEST_BASE_SAAS_API } from "@/api/common";

console.log("VITE_REQUEST_BASE_SAAS_API:", VITE_REQUEST_BASE_SAAS_API);

const mockUrlList = mockList.map(item => {
  return item.url;
});

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  // 请求超时时间
  timeout: 10000,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json"
  },
  // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
  paramsSerializer: {
    serialize: stringify as unknown as CustomParamsSerializer
  }
};

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }

  /** token过期后，暂存待执行的请求 */
  private static requests = [];

  /** 防止重复刷新token */
  private static isRefreshing = false;

  /** 初始化配置对象 */
  private static initConfig: PureHttpRequestConfig = {};

  /** 保存当前Axios实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig) => {
        // console.log("config:", config);

        const mock = useUserStoreHook().mock;

        if (mock === "1") {
          // 演示数据
          const shortUrl = config.url.replace(VITE_REQUEST_BASE_SAAS_API, "");
          // console.log("shortUrl:", shortUrl);
          const mockShortUrl = mockUrlList.find(mUrl => {
            return mUrl.includes(shortUrl);
          });

          if (mockShortUrl) {
            // console.log("mockShortUrl:", mockShortUrl);
            config.url = mockShortUrl;
          }
        } else {
          if (config.url.includes("analyse.wanhuhealth.com")) {
            config.url = config.url.replace(
              "analyse.wanhuhealth.com",
              "39.107.125.188:81"
            );
          }
        }

        // 开启进度条动画
        NProgress.start();
        // 优先判断post/get等方法是否传入回掉，否则执行初始化设置等回掉
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback(config);
          return config;
        }
        if (PureHttp.initConfig.beforeRequestCallback) {
          PureHttp.initConfig.beforeRequestCallback(config);
          return config;
        }

        // console.log("config:", config);
        // 当没有配置beforeRequestCallback时，会验证token，一定设置了beforeRequestCallback，就不再验证token是否过期了。这种逻辑似乎有点问题？

        /** 请求白名单，放置一些不需要token的接口（通过设置请求白名单，防止token过期后再请求造成的死循环问题） */
        const whiteList = [
          "/login",
          "analyse.wanhuhealth.com",
          "39.107.125.188:81"
        ];

        // console.log('config:',config);

        return whiteList.some(v => config.url.indexOf(v) > -1)
          ? config
          : new Promise(resolve => {
              const data = getToken();
              // console.log("getToken data:", data);
              if (data) {
                // 带上token
                config.headers["Authorization"] = formatToken(data.accessToken);
                resolve(config);
              } else {
                // 没有token且不再白名单，现在直接放行了，感觉有点问题？
                resolve(config);
              }
            });
      },
      error => {
        console.log("http error:", error);
        return Promise.reject(error);
      }
    );
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = PureHttp.axiosInstance;
    instance.interceptors.response.use(
      (response: PureHttpResponse) => {
        // console.log('response:',response)
        const $config = response.config;
        // 关闭进度条动画
        NProgress.done();
        // 优先判断post/get等方法是否传入回掉，否则执行初始化设置等回掉
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return response.data;
        }
        if (PureHttp.initConfig.beforeResponseCallback) {
          PureHttp.initConfig.beforeResponseCallback(response);
          return response.data;
        }
        // console.log("response", response);
        // 万户自己的后端接口
        if (
          response.config.url.includes(VITE_REQUEST_BASE_SAAS_API) ||
          response.config.url.includes("/mock/")
        ) {
          if (response.data && response.data.code === 0) {
            return response.data.data;
          } else {
            ElMessageBox.alert(response.data.message || "请求失败", "错误", {
              confirmButtonText: "确定"
            });
            return response.data;
          }
        } else {
          // 第三方接口
          // console.log('response.data:',response.data)
          if (response.data) {
            return response.data;
          } else {
            ElMessageBox.alert("请求失败", "错误", {
              confirmButtonText: "确定"
            });
            return response.data;
          }
        }
      },
      (error: PureHttpError) => {
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        // 关闭进度条动画
        NProgress.done();
        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject($error);
      }
    );
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<T> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig;

    // 单独处理自定义请求/响应回掉
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch(error => {
          reject(error);
        });
    });
  }

  /** 单独抽离的post工具函数 */
  public post<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("post", url, params, config);
  }

  /** 单独抽离的get工具函数 所有的get请求带上userId*/
  public get<T>(
    url: string,
    data: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): Promise<T> {
    if (!data.params.userId) {
      data.params.userId = useUserStoreHook().userInfo.user;
    }
    if (!data.params.isNationwide) {
      data.params.isNationwide = useUserStoreHook().userRegions.isNationwide;
    }
    return PureHttp.axiosInstance.get(url, { ...data, ...config });
  }

  public postForm<P>(
    url: string,
    params?: AxiosRequestConfig,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    // console.log("postForm params:", params);
    const tempConfig = config
      ? Object.assign(config, {
          headers: { "content-type": "application/x-www-form-urlencoded" }
        })
      : {
          headers: { "content-type": "application/x-www-form-urlencoded" }
        };
    return PureHttp.axiosInstance.postForm(url, params, tempConfig);
  }
}

export const http = new PureHttp();
